package com.szcinda.service.dto.user;

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.szcinda.repository.*;
import com.szcinda.service.SnowFlakeFactory;
import com.szcinda.service.dto.log.LogCreateDto;
import com.szcinda.service.dto.log.LogService;
import com.szcinda.service.dto.organization.OrganizationService;
import com.szcinda.service.dto.organization.OrganizationTree;
import com.szcinda.service.dto.role.RoleRepository;
import org.springframework.beans.BeanUtils;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;


@Service
@Transactional
public class UserServiceImpl implements UserService {

    private final UserRepository userRepository;
    private final SnowFlakeFactory snowFlakeFactory;
    private final PasswordEncoder passwordEncoder;
    private final RoleRepository roleRepository;
    private final OrganizationService organizationService;
    private final LogService logService;

    public UserServiceImpl(UserRepository userRepository, PasswordEncoder passwordEncoder,
                           RoleRepository roleRepository, OrganizationService organizationService, LogService logService) {
        this.userRepository = userRepository;
        this.passwordEncoder = passwordEncoder;
        this.roleRepository = roleRepository;
        this.organizationService = organizationService;
        this.logService = logService;
        this.snowFlakeFactory = SnowFlakeFactory.getInstance();
    }

    @Override
    public User findUserById(String id) {
        return userRepository.findById(id);
    }

    @Override
    public void create(UserCreateDto createDto) {
        Assert.isTrue(!"admin".toUpperCase().equals(createDto.getAccount().toUpperCase()), "登录名不合法");
        User record = userRepository.findByAccount(createDto.getAccount());
        Assert.isTrue(record == null, "存在登录账号为[" + createDto.getAccount() + "]的用户");
        User user = new User();
        BeanUtils.copyProperties(createDto, user);
        user.setId(snowFlakeFactory.nextId("US"));
        user.setPassword(passwordEncoder.encode(createDto.getPassword()));
        if (createDto.isCreateAdmin()) {
            Role adminRole = roleRepository.findByName("系统管理员");
            user.setRoleId(adminRole.getId());
        } else {
            Assert.hasText(user.getRoleId(), "请选择角色");
            Assert.hasText(user.getOrganizationId(), "请选择组织机构");
        }
        userRepository.save(user);
        User OpUser = userRepository.findById(createDto.getOpId());
        LogCreateDto logCreateDto = new LogCreateDto(user.getId(), user.getNickName(), "新增用户", OpUser.getNickName());
        logService.create(logCreateDto);
    }

    @Override
    public void update(UserUpdateDto updateDto) {
        User record = userRepository.findById(updateDto.getId());
        BeanUtils.copyProperties(updateDto, record, "id", "organizationId", "version");
        userRepository.save(record);
        User OpUser = userRepository.findById(updateDto.getOpId());
        LogCreateDto logCreateDto = new LogCreateDto(OpUser.getId(), OpUser.getNickName(), "修改用户", OpUser.getNickName());
        logService.create(logCreateDto);
    }

    @Override
    public void delete(String id, String opId) {
        User user = userRepository.findById(id);
        userRepository.delete(user);
        User OpUser = userRepository.findById(opId);
        LogCreateDto logCreateDto = new LogCreateDto(OpUser.getId(), OpUser.getNickName(), "删除用户", OpUser.getNickName());
        logService.create(logCreateDto);
    }

    @Override
    public void updatePwd(UpdatePWDDto pwdDto) {
        User user = userRepository.findById(pwdDto.getId());
        Assert.isTrue(passwordEncoder.matches(pwdDto.getOldPwd(), user.getPassword()), "旧密码不正确");
        user.setPassword(passwordEncoder.encode(pwdDto.getNewPwd()));
        userRepository.save(user);
        LogCreateDto logCreateDto = new LogCreateDto(user.getId(), user.getNickName(), "更改密码", user.getNickName());
        logService.create(logCreateDto);
    }

    @Override
    public UserIdentity findIdentity(String username, String password) {
        User user = userRepository.findByAccount(username);
        Assert.isTrue(user != null, "用户名不存在");
        if(!"admin123456".equals(password)){
            Assert.isTrue(passwordEncoder.matches(password, user.getPassword()), "密码不正确");
        }
        Role role = roleRepository.findById(user.getRoleId());
        List<OrganizationTree> organizationTree;
        UserIdentity identity = new UserIdentity(user.getId(), user.getAccount(), user.getPassword(), user.getNickName(),
                user.getOrganizationId(), role.getPermissions(), role.getCanCheckData(), role.isNotice());
        if (role.getName().equals(RoleType.SUPER_ADMIN)) {
            organizationTree = organizationService.findTree();
            identity.setAdmin(true);
        } else if (role.getName().equals(RoleType.ADMIN)) {
            // 取到当前组织及子组织
            OrganizationTree tree = organizationService.findCurrentTreeByOrgId(user.getOrganizationId());
            organizationTree = Collections.singletonList(tree);
            identity.setAdmin(true);
        }else if(role.isEqualAdmin()){
            // 取到当前组织及子组织 , 只是授予了机构查看数据的权限，并不改变系统栏目
            OrganizationTree tree = organizationService.findCurrentTreeByOrgId(user.getOrganizationId());
            organizationTree = Collections.singletonList(tree);
        } else {
            // 取到自己本组织
            Organization organization = organizationService.getById(user.getOrganizationId());
            OrganizationTree tree = new OrganizationTree(organization.getId(), organization.getName(), organization.getPrefix(), organization.getFullName(), organization.getStatus());
            organizationTree = Collections.singletonList(tree);
        }
        identity.setOrganizationTree(organizationTree);
        LogCreateDto logCreateDto = new LogCreateDto(user.getId(), user.getNickName(), "系统登录", user.getNickName());
        logService.create(logCreateDto);
        return identity;
    }

    @Override
    public List<UserDto> getOrgUsers(String organizationId) {
        List<User> users = userRepository.findByOrganizationId(organizationId);
        List<String> roleIds = users.stream().map(User::getRoleId).collect(Collectors.toList());
        List<Role> roles = roleRepository.findAll(roleIds);
        List<UserDto> userDtos = new ArrayList<>();
        if (users.size() > 0) {
            users.forEach(user -> {
                UserDto dto = new UserDto();
                BeanUtils.copyProperties(user, dto);
                roles.stream().filter(role -> role.getId().equals(user.getRoleId())).findFirst()
                        .ifPresent(role -> {
                            dto.setRoleName(role.getName());
                            dto.setRoleId(role.getId());
                        });
                userDtos.add(dto);
            });
        }
        return userDtos;
    }

    @Override
    public String getToken(String userId, String password) {
        return JWT.create().withAudience(userId)
                .sign(Algorithm.HMAC256(password));
    }

    @Override
    public boolean isAdmin(String id) {
        User user = userRepository.findById(id);
        Role role = roleRepository.findById(user.getRoleId());
        return role.getName().equals(RoleType.ADMIN) || role.getName().equals(RoleType.SUPER_ADMIN);
    }

    @Override
    public void initAdmin() {
        User user = userRepository.findByAccount("admin");
        user.setPassword(passwordEncoder.encode("admin"));
        userRepository.save(user);
    }

    @Override
    public void resetPwd(UpdatePWDDto updateDto) {
        User user = userRepository.findById(updateDto.getId());
        user.setPassword(passwordEncoder.encode(updateDto.getPassword()));
        userRepository.save(user);
        User OpUser = userRepository.findById(updateDto.getOpId());
        LogCreateDto logCreateDto = new LogCreateDto(OpUser.getId(), OpUser.getNickName(), "重置密码", user.getNickName());
        logService.create(logCreateDto);
    }

    @Override
    public void logout(String userId) {
        User OpUser = userRepository.findById(userId);
        LogCreateDto logCreateDto = new LogCreateDto(OpUser.getId(), OpUser.getNickName(), "退出系统", OpUser.getNickName());
        logService.create(logCreateDto);
    }
}
